module arm.stk;


/**
* Cortex-M SysTick Timer
*/

/**
* 系统时钟定时器
* 24bit 
*/

import chip;
import chipconf:ChipCfg = ChipConfig;

/**
* 频率定义
*/
enum STK_TickFreq
{
    Freq_1Hz =      1,              /// 1s
    Freq_10HZ =     10,             /// 100ms
    Freq_100Hz =    100,            /// 10ms
    Freq_1KHz =     1000,           /// 1ms
    Freq_10KHz =    10_000,         /// 100us
    Freq_100KHz =   100_000,        /// 10us
    Freq_1MHz =     1_000_000,       /// 1us
    Freq_10MHz =    10_000_000,      /// 100ns
    Freq_100MHz =   100_000_000,     /// 10ns
    Freq_1GHz =     1000_000_000,    /// 1ns
}

/**
* SysTick 配置结构体
* Params:
*   EnableInt = 是否使能中断
*   freq = 时钟频率
*/
struct STK_Conf{
    import arm.cortex_m;
    /// 使能中断
    bool EnableInt;
    /// 时钟频率
    STK_TickFreq TickFreq;
    /// 自动初始化
    bool AutoInit;
    /// 附加回调函数
    CallHandler Chandler;
    /// 回调数量
    size_t      handlerSize;
}


private enum bool hasBusPeriph = HasPeriph!("STK");
static if(hasBusPeriph):

import arm.cortex_m;
import arm.bus;
import core.attribute;

private
{
    /// 回调函数数量
    enum CallHandlerSize = 1;
    __gshared CallHandler CallHandlers;

    __gshared uint mTick;

    
    enum maxfreq = 0x7FFF_FFF0u;

    //enum STK_Conf mConf = GetConfig!("Config_STK");
    enum STK_Conf mConf = ChipCfg.Config_STK;
    /// 重载修正值,补偿执行时间 ,未实现
    enum reloadFix = 5;
}


static interface  STK //: MMIOBus!(Peripherals.STK)
{
    /// 检查配置是否合法
    private
    {
        enum STK_Type* mBase = Peripherals.STK;
        //enum shared(STK_Type*) sBase = Peripherals.STK;

        //static if(mConf.AutoInit)
        pragma(crt_constructor,CrtPriority!(FlagCrt.STK,0))
        static this()
        {
            import arm.utils:EncodePriority;
            
            
            enum mFreq = ChipCfg.HCLK_Frequency / mConf.TickFreq;
            static assert(mFreq,"SysTick Freq is too low");
            static assert(mFreq <= maxfreq,"SysTick Freq is too high freq:");
            

            STK.setClockFreq(mFreq);
            //static if(mConf.EnableInt)
            
            import arm.hal;
            import arm.scb;
            auto encode = EncodePriority(SCB.PriorityGroup(),15,0);
            /// 设置权限
            SCB.Priority!(IRQn_Core.SysTick_IRQn)(encode);
            /// 设置优先级
            
            //HAL.PrioritySet(IRQn_Core.SysTick_IRQn,STK.Priority,0);
        

        }

    }
    public{
        /// 优先级
        enum Priority = 15;
        //enum STK_Conf Conf =
    }

    /**
        * 设定系统计时器时钟频率
        * Params: 
        *   freq = 目标频率 $(D hz) 
        *   ahb = 当前AHB时钟频率$(D hz)
    */
    static void setClockFreq(uint freq,uint ahb)
    {
        uint ratio = ahb/freq;
        setClockFreq(ratio);
    }
    
    static void setClockFreq(uint freq)
    {
        //STK_Type.mask_CTRL ctrl;

        //mBase.CTRL = 0;                     /// 停止原有计数器
        auto mCtrl = mBase.CTRL;
        //Direct_GetCountFlag();                     /// 清理计数器翻转标志
        mCtrl = 0x00;                       /// 清空
        mCtrl.TICKINT = 1;                  /// 使能中断
        mCtrl.ENABLE = 1;                   /// 使能计数器

        if(freq >= STK_Type.mask_LOAD.RELOAD){
            freq /=8;
        }else{
            //ctrl |= STK_Type.mask_CTRL.CLKSOURCE;
            mCtrl.CLKSOURCE = 1;
        }

        mBase.LOAD.RELOAD = freq - 1 - reloadFix;   // 设定新重载值
        mBase.VAL.CURRENT = 0;
        mBase.CTRL = mCtrl;
    }

    /**
    * 由`cALIB`参数决定定时器
    * todo:未实现
    */
    static void setClockFreqByTenms()
    {
    }


    static uint GetClockFreq()
    {
        auto reload = mBase.LOAD.RELOAD() ;
        bool isAHB = (mBase.CTRL.CLKSOURCE() == 0);
        auto freq = (reload + 1) * (isAHB ? 1 : 8);
        return freq;
    }

    /// 判断是否使能
    static bool isEnable() => (mBase.CTRL.ENABLE() != 0);
    
    /// 禁止
    static void Disable() => (mBase.CTRL.ENABLE(0));
    /// 开启
    static void Enable() => (mBase.CTRL.ENABLE(1));
    /// 获取sysTick计数值
    static uint GetTick() => mTick;
    /// 获取当前计数值
    static uint GetCurrent() => (mBase.VAL.CURRENT());
    /// 获取重载值
    static uint GetReload() => (mBase.LOAD.RELOAD());
    /// 获取时钟频率
    static uint GetTenms() => (mBase.CALIB.TENMS());
    pragma(inline,true)
    static bool GetCountFlag() => (mBase.CTRL.COUNTFLAG() != 0);



}

alias SysTick = STK;


@weak
extern(C) void SysTick_Handler() @system
{
    mTick += mConf.TickFreq;
};


///pragma(msg,__traits(allMembers, CorePeripheral.STK.mask_CTRL));


